-- Dialog
-- create by chengb
-- 对话框相关工具函数

require "game/ui/form/common/UIScreenShining"
require "game/ui/form/common/UIInvisibleForm"
require "game/ui/dialog/UIConfirm2"
require "game/ui/dialog/UIConfirm3"
require "game/ui/dialog/UIConfirm4"
require "game/ui/form/dungeon/UICommunicating"
require "game/ui/form/common/UIBonusNotify"
require "game/ui/form/dungeon/UIDungeonBuyLife"
require "game/ui/form/common/UILoadingEffect"
require "game/ui/form/dungeon/UIDungeonMgr"
require "game/ui/form/setting/UIGameBoard"

-- 飘字提示，适用于简短的消息提示
function alert(msg, delay, stayTime)
    if msg == nil or msg == "" then
        return;
    end

    local function doAlert(msg, delay, startTime)
        local function callback()
            local w = AlignM.frameSize.width;
            local h = AlignM.frameSize.height;
            local tipStayTime = stayTime or 0;

            -- 飘字
            local text = ccui.Text:create();
            text:setPosition(cc.p(w / 2, h * 0.66));

            -- 设置文本自动换行
            TextStyleM.setOutlineStyle(text, 3, TextStyleM.TEXT_OUTLINE_COLOR_DARK);
            TextStyleM.setTextStyle(text, 36, TextStyleM.TEXT_COLOR_ORANGE, true, -3);
            text:enableShadow(TextStyleM.TEXT_OUTLINE_COLOR_DARK, cc.size(3, -3));
            text:getVirtualRenderer():setMaxLineWidth(TextStyleM.TEXT_WORD_COUNT_PER_LINE * 30);
            text:setString(msg);

            -- 设置文本横向对齐方式 居中对齐
            text:setScale(w/DESIGN_WIDTH);
            text:setTextHorizontalAlignment(cc.TEXT_ALIGNMENT_CENTER);

            local callfunc = cc.CallFunc:create(function()
                performWithDelay(UIMgr:getCurrentScene(), function() UIMgr:getCurrentScene():removeEffect(text) end, tipStayTime);
            end);

            local moveBy = cc.MoveBy:create(1, cc.p(0, 40));
            local scale  = text:getScale();
            local scaleUp  = cc.ScaleTo:create(0.2, 1.1 * scale);
            local scaleDown  = cc.ScaleTo:create(0.05, 1 * scale);
            text:runAction(cc.Sequence:create(scaleUp, scaleDown, moveBy, callfunc));

            UIMgr:getCurrentScene():addEffect(text);
        end

        if delay == nil then
            callback();
        else
            performWithDelay(UIMgr:getCurrentScene(), callback, delay);
        end
    end

    -- 排队机制，多条同时触发时，间隔0.5秒顺序播放
    local scene = UIMgr:getCurrentScene();
    scene.AlertList = scene.AlertList or {};
    table.insert(scene.AlertList, { msg = msg, delay = delay, stayTime = stayTime });

    local function play()
        if #scene.AlertList > 0 then
            scene.isAlertPlaying = true;

            local para = scene.AlertList[1];
            table.remove(scene.AlertList, 1);
            doAlert(para.msg, para.delay, para.stayTime);
            performWithDelay(scene, play, 0.5);
        else
            scene.isAlertPlaying = false
        end
    end

    if not scene.isAlertPlaying then
        play();
    end
end

-- 飘字提示2，适用于简短的消息提示，文字支持多彩文本
-- 效果和alert略有区别，主要是描边稍微细了些 ，阴影效果是模拟的没那么连续
function alert2(msg, delay, stayTime)
    if msg == nil or msg == "" then
        return;
    end

    local function callback()
        local w = AlignM.frameSize.width;
        local h = AlignM.frameSize.height;
        local tipStayTime = stayTime or 0;

        local node = cc.Node:create();
        node:setPosition(cc.p(w / 2, h * 0.66));

        local function createText()
            local textLabel = ccui.Text:create();

            -- 设置文本自动换行
            TextStyleM.setTextStyle(textLabel, 36, TextStyleM.TEXT_COLOR_ORANGE, true);
            TextStyleM.setOutlineStyle(textLabel, 2, TextStyleM.TEXT_OUTLINE_COLOR_DARK);
            textLabel:getVirtualRenderer():setMaxLineWidth(TextStyleM.TEXT_WORD_COUNT_PER_LINE * 30);

            -- 设置文本横向对齐方式 居中对齐
            textLabel:setScale(w/DESIGN_WIDTH);
            textLabel:setTextHorizontalAlignment(cc.TEXT_ALIGNMENT_CENTER);
            return textLabel;
        end

        -- 飘字
        local textLabel = createText();

        -- 阴影节点
        local shadowLabel = createText();
        TextStyleM.setTextStyle(shadowLabel, 36, TextStyleM.TEXT_OUTLINE_COLOR_DARK, true);
        shadowLabel:setPosition(shadowLabel:getPositionX()+3, shadowLabel:getPositionY()-3);
        shadowLabel:setString(extractString(msg));

        node:addChild(shadowLabel);

        applyString2(textLabel, msg);
        node:addChild(textLabel);

        local callfunc = cc.CallFunc:create(function()
            performWithDelay(UIMgr:getCurrentScene(), function() UIMgr:getCurrentScene():removeEffect(node) end, tipStayTime);
        end);

        local moveBy = cc.MoveBy:create(1, cc.p(0, 40));
        local scale  = node:getScale();
        local scaleUp  = cc.ScaleTo:create(0.2, 1.1 * scale);
        local scaleDown  = cc.ScaleTo:create(0.05, 1 * scale);
        node:runAction(cc.Sequence:create(scaleUp, scaleDown, moveBy, callfunc));

        UIMgr:getCurrentScene():addEffect(node);
    end

    if delay == nil then
        callback();
    else
        performWithDelay(UIMgr:getCurrentScene(), callback, delay);
    end
end

-- 拆分飘字
function splitAlert(msgList, timeDur)
    if #msgList <= 0 then
        -- 没有内容
        return;
    end

    local dur = timeDur or 1;

    if type(msgList) == "string" then
        -- 直接飘字
        alert(msgList);
    elseif type(msgList) == "table" then
        for index, msg in pairs(msgList) do
            local function callback()
                alert(msg);
            end
            -- 延迟飘字
            performWithDelay(UIMgr:getCurrentScene(), callback, (index - 1) * dur);
        end
    end
end

-- 显示信息框
function showHint(msg, autoClose, callback, hasBg)
    if autoClose == nil then
        autoClose = true;
    end

    local UIHint = require "game/ui/dialog/UIHint";
    local hint = UIHint.create("", msg, true, autoClose, callback, hasBg);
    UIMgr.getCurrentScene():addDialog(hint);
end

-----------------------------------
-- 显示信息框, 有标题，默认可点击跳过
-- @param title    标题
-- @param msg      内容
-- @param isCover  是否覆盖上一次的信息框
function showHint2(title, msg, isCover)
    local UIHint = require "game/ui/dialog/UIHint";
    if isCover then
        local dialog = UIMgr.getCurrentScene():getCurrentDialog();
        if dialog and dialog:getName() == "UIHint" then
            UIMgr.getCurrentScene():removeDialog(dialog);
        end
    end

    local hint = UIHint.create(title, msg, true);
    UIMgr.getCurrentScene():addDialog(hint);
end

-- 加载框
local uiLoadingForm = nil;

-- 显示加载框
function showLoadingForm()
    hideLoadingForm();

    if uiLoadingForm == nil then
        local UIHint = require "game/ui/dialog/UIHint";
        uiLoadingForm = UIHint.create("", getLocStr("entering"), false, false);
    end

    UIMgr.getCurrentScene():addDialog(uiLoadingForm);
end

-- 隐藏加载框
function hideLoadingForm()
    if uiLoadingForm ~= nil then
        UIMgr.getCurrentScene():removeDialog(uiLoadingForm);
        uiLoadingForm = nil;
    end
end

-------------------------------------------------------------------------------
-- 弹出确认提示框
-- @param msg        提示框的内容
-- @param okFunc     点击确认的处理函数
-- @param okArgs     okFunc所需的参数列表（当参数较多时，这里通常传入table类型）
-- @param cancelFunc 点击取消的处理函数
-- @param cancelArgs cancelFunc所需的参数列表（当参数较多时，这里通常传入table类型）
-- @param okText     确定按钮文本
function confirm(msg, okFunc, okArgs, cancelFunc, cancelArgs, okText)
    local UIConfirm = require "game/ui/dialog/UIConfirm";
    local confirm = UIConfirm.create(msg, okFunc, okArgs, cancelFunc, cancelArgs, okText);
    UIMgr.getCurrentScene():addDialog(confirm);
end

-------------------------------------------------------------------------------
-- 弹出确认提示框
-- @param type       提示类型
-- @param title      提示框标题
-- @param msg        提示框内容
-- @param okFunc     点击确认的处理函数
-- @param cancelFunc 点击取消的处理函数
-- @param okText     确定按钮文本
-- @param cancelText 取消按钮文本
-- @param extraPara  附加参数（目前支持传入：okColor, cancelColor, backFunc）
function confirm2(type, title, msg, okFunc, cancelFunc, okText, cancelText, extraPara)
    local UIConfirm = require "game/ui/dialog/UIConfirm2";
    local confirm = UIConfirm2.create(type, title, msg, okFunc, cancelFunc,
        okText, cancelText, extraPara);
    UIMgr.getCurrentScene():addDialog(confirm);
    return confirm;
end


-------------------------------------------------------------------------------
-- 弹出确认提示框
-- @param type       提示类型
-- @param title      提示框标题
-- @param msg        提示框内容(msg为table，有三段文本，)
-- @param iconPath   图标路径(iconPath为table，有两个)
-- @param okFunc     点击确认的处理函数
-- @param cancelFunc 点击取消的处理函数
-- @param okText     确定按钮文本
-- @param cancelText 取消按钮文本
-- @param extraPara  附加参数（目前支持传入：okColor, cancelColor, backFunc）
function confirm3(type, title, msg, iconPath, okFunc, cancelFunc, okText, cancelText, extraPara)
    local UIConfirm = require "game/ui/dialog/UIConfirm3";
    local confirm = UIConfirm3.create(type, title, msg, iconPath, okFunc, cancelFunc,
        okText, cancelText, extraPara);
    UIMgr.getCurrentScene():addDialog(confirm);
    return confirm;
end

-------------------------------------------------------------------------------
-- 弹出确认提示框
-- @param type       提示类型
-- @param title      提示框标题
-- @param msg        提示框内容
-- @param okFunc     点击确认的处理函数
-- @param cancelFunc 点击取消的处理函数
-- @param okText     确定按钮文本
-- @param cancelText 取消按钮文本
-- @param extraPara  附加参数（目前支持传入：okColor, cancelColor, backFunc）
function confirm4(type, title, msg, okFunc, cancelFunc, okText, cancelText, extraPara)
    local UIConfirm = require "game/ui/dialog/UIConfirm2";
    local confirm = UIConfirm4.create(type, title, msg, okFunc, cancelFunc,
        okText, cancelText, extraPara);
    UIMgr.getCurrentScene():addDialog(confirm);
    return confirm;
end

-- 提示购买体力
function confirmBuyLife(needCancel)
    UIMgr.getCurrentScene():removeFormByName("UIDungeonBuyLife");
    local uiBuyLife = UIDungeonBuyLife.create(needCancel);
    UIMgr.getCurrentScene():addForm(uiBuyLife);
end

-- 显示钻石不足确认框
function showGemLackConfirm()
    local msg = getLocStr("buy_gem_confirm");

    local function buyGem()
        if not MarketM.isRechargeOpen() then
            -- 充值功能暂未开放
            confirm2(CONFIRM_TYPE_OK, getLocStr("slime_note"), getLocStr("recharge_close_tip"));
            return;
        end

        -- 打开充值界面
        local uiMarketMain = UIMgr.getCurrentScene():getFormByName("UIMarketMain");
        if uiMarketMain == nil then
            uiMarketMain = UIMarketMain.create();
            UIMgr.getCurrentScene():addForm(uiMarketMain);
            uiMarketMain:showRechargePage();
        else
            uiMarketMain:showRechargePage();
        end
    end

    confirm2(CONFIRM_TYPE_OK, getLocStr("slime_note"), msg,
        buyGem, nil, getLocStr("btn_text_go"));
end

-- 获取奖励描述
function getBonusDesc(bonus)
    local strGain = "";
    local name;
    if 1 == bonus[1] then
        -- 物品奖励
        name = ItemM.query(bonus[2], "name");
        strGain = string.format(getLocStr("item_bonus_format"), name, bonus[3]);
    elseif 2 == bonus[1] then
        -- 属性奖励
        name = FieldsM.getFieldName(bonus[2]);
        strGain = string.format(getLocStr("attrib_bonus_format"), name, bonus[3]);
    elseif 3 == bonus[1] then
        -- 英雄奖励
        name = PetM.query(bonus[2], "name");
        strGain = string.format(getLocStr("hero_bonus_format"), bonus[3], name);
    else
        -- 其他奖励暂不处理
        trace("Dilaog", "未知的奖励格式 ！");
    end

    return strGain;
end

-- 显示全屏星光特效界面
function showScreenShining()
    local uiForm = UIScreenShining.create();
    UIMgr.getCurrentScene():removeFormByName("UIScreenShining");
    UIMgr.getCurrentScene():addForm(uiForm);
end

-- 等待N秒
function wait(duration, callback, zOrder)
    local uiForm = UIInvisibleForm.create(duration, callback, zOrder);
    UIMgr.getCurrentScene():addForm(uiForm);
end

-- 金币不足购买提示
function showBuyMoneyTip()
    local function okFun()
        local uiMarketMain = UIMarketMain.create();
        UIMgr.getCurrentScene():removeFormByName("UIMarketMain");
        UIMgr.getCurrentScene():addForm(uiMarketMain);
        uiMarketMain:showSubPage("resource", true);
    end

    confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("slime_note_title"),
       getLocStr("buy_money_tip"), okFun, nil, getLocStr("btn_text_ok"), getLocStr("btn_text_back"),
       { ["cancelColor"] = "blue" });
end

-- 提示进入下一层扣除体力
function showCostLifeInDungeon()
    local lifeCost = FormulaM.invoke("CALC_BOSS_LAYER_COST_LIFE");

    -- 继续探险函数
    local function okFun()
        if ME.user.dbase:query("life", 0) < lifeCost then
            -- 弹出购买体力提示
            confirmBuyLife(true);
            return;
        else
            -- 已经废除
        end
    end

    -- 体力购买函数
    local function buyLifeFun()
        -- 弹出购买体力提示
        confirmBuyLife(true);
    end

    -- 取消函数
    local function cancelFun()
        -- 弹出离开迷宫确认提示框
        confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("leave_dungeon"),getLocStr("leave_dungeon_tip"),
            UIDungeonMgr.leaveDungeon, nil, getLocStr("btn_text_leave_dungeon"), getLocStr("btn_text_in_dungeon"),
            { ["okColor"] = "blue" });
            AudioM.playFx("button_spell");
    end

    local extraPara = { };
    local msg;

    if ME.user.dbase:query("life", 0) >= lifeCost then
        msg = string.format(getLocStr("boss_layer_cost_life_msg"), lifeCost,
            ME.user.dbase:query("life", 0), ME.user:getMaxLife());
    else
        extraPara = { ["lifeRecoverTime"] = true};

        local leftTime = math.floor(UserM.getLifeRecoveryLeftTime());
        local secs = leftTime % 60;
        local mins = math.floor(leftTime / 60);

        msg = string.format(getLocStr("boss_layer_cost_life_msg2"), lifeCost, mins, secs);
    end

    if ME.user.dbase:query("life", 0) >= lifeCost then
        -- 弹出提示框
        confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("slime_note_title"), msg, okFun,
            cancelFun, getLocStr("btn_text_still_in"), nil, extraPara);
    else
        -- 弹出提示框
        confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("slime_note_title"), msg, buyLifeFun,
            cancelFun, getLocStr("btn_text_bug_life"), nil, extraPara);
    end
end

----------------------
-- 显示通信中界面
-- @param title 标题（默认为：通信中）
-- @param showTips 是否显示小贴士
-- @param pauseEffect 显示暂离效果
-- @param timeout  超时时间（如果传入超时时间，则定时关闭界面）
function showCommunicatingForm(title, showTips, pauseEffect, timeout, titleType, startDungeon)
    UIMgr.getCurrentScene():removeFormByName("UICommunicating");
    local uiCommunicating = UICommunicating.create(title, showTips, pauseEffect, timeout, titleType, startDungeon);
    UIMgr.getCurrentScene():addForm(uiCommunicating);
end

-- 关闭通信中界面
function closeCommunicatingForm(getTip)
    getTip = getTip or true;
    local function removeForm()
        UIMgr.getCurrentScene():removeFormByName("UICommunicating");

        -- 关闭界面，获取下一条随机贴士
        if getTip then
            LoadingTipsM.nextRandomTip();
        end
    end

    local delay = 0.01;
    local uiForm = UIMgr.getCurrentScene():getFormByName("UICommunicating");
    if uiForm then
        delay = uiForm.showTips and 1.5 or 0.01;
    end
    performWithDelay(UIMgr.getCurrentScene(), removeForm, delay);

    -- 抛出事件
    EventMgr.fire(event.CLOSE_COMMUNICATE_FORM);

    return delay;
end

-- 显示加载动画
function addLoadingEffect()
    if UIMgr:getCurrentScene():getFormByName("UILoadingEffect") then
        return;
    end

    local UILoadingEffect = UILoadingEffect.create();
    UIMgr.getCurrentScene():addForm(UILoadingEffect);
end

-- 去掉加载动画
function removeLoadingEffect()
    UIMgr:getCurrentScene():removeFormByName("UILoadingEffect");
end

----------------------
-- 显示获得奖励框
-- @param title       标题
-- @param bonusList   奖励列表
-- @param okFunc      点击确定按钮的回调函数
-- @param msg         奖励描述
-- @param okText      确认按钮文本
-- @param enable      是否可用
-- @param needBackBtn 是否显示返回按钮
-- @param exitFunc    界面关闭时的回调函数
function showBonusNotifyForm(title, bonusList, okFunc, msg, okText, enable, needBackBtn, exitFunc, extraPara)
    local uiBonusForm = UIBonusNotify.create(title, bonusList, okFunc, msg, okText, enable, needBackBtn, exitFunc, extraPara);
    UIMgr.getCurrentScene():addForm(uiBonusForm);
    -- 播放界面音效
    AudioM.playFx("button_receive");
end

----------------------
-- 拆分字符(将字符串中的所有英文单词拆分出来)
-- @param szFullString  待拆分字符串
function splitWordsFromString(szFullString)
    local words = {}
    for w in string.gfind(szFullString, "%w+", "%w") do
        table.insert(words, w)
    end
    return words;
end

-- 弹出登录Google游戏中心的对话框
function showConnectGoogleDialog(title, msg)
    local function okFunc()
        showGoogleLogin();
    end
    confirm2(CONFIRM_TYPE_OK, title, msg, okFunc);
end

-- 弹出登录亚马逊游戏中心的对话框
function showConnectAmazonDialog(title, msg)
    local function okFunc()
        showAmazonLogin();
    end
    confirm2(CONFIRM_TYPE_OK, title, msg, okFunc);
end

----------------------
-- 通用说明界面（使用公告界面模板）
-- @param title     主标题
-- @param subhead   副标题
-- @param content   内容
function commonExplain(title, subhead, content)
    local data = {
        ["title"] = title,
        ["subhead"] = subhead,
        ["content"] = content,
    };
    local uiGameBoard = UIGameBoard.create(data);
    UIMgr.getCurrentScene():addForm(uiGameBoard);
end

---------------------
-- 公告界面
-- @param boardId   公告ID
function showGameBoard(boardId)
    -- 根据语言版本选公告内容
    local board = GameBoardM.getGameBoardContentById(boardId);
    local data = {
        ["title"] = board["title"],
        ["subhead"] = board["showTime"],
        ["content"] = board["content"],
        ["boardId"] = boardId,
        ["activity"] = board["activity"],
    };
    UIMgr.getCurrentScene():removeFormByName("UIGameBoard");
    local uiGameBoard = UIGameBoard.create(data);
    UIMgr.getCurrentScene():addForm(uiGameBoard);
end

----------------------
-- 通用资源包下载界面
-- @param title        主标题
-- @param desc         内容
-- @param targetPart   目标资源包名称
-- @param callback     回调函数
function downloadPkg(title, desc, targetPart, callback)
    local partName = targetPart;
    local needShowUI = false;
    if cc.UserDefault:getInstance():getStringForKey(partName) ~= "1" then
        needShowUI = true;
    end

    if not needShowUI then
        if callback then
            callback(true);
        end

        return;
    end

   -- 显示下载界面
    local function showDownloadUI()
        -- 显示资源包下载界面
        require "game/ui/form/download/UIPkgDownload";

        -- 防止重复点击下载
        local uiForm = UIMgr.getCurrentScene():getFormByName("UIPkgDownload");
        if uiForm then
            cclog("资源下载中");
            return;
        end

        local uiDialog = UIPkgDownload.create(title, desc, targetPart, callback);
        -- UIMgr.getCurrentScene():addDialog(uiDialog);
        UIMgr.getCurrentScene():addForm(uiDialog);

        -- 抛出开始分包下载事件
        EventMgr.fire(event.BEGIN_PKG_DOWNLOAD, { ["targetPart"] = targetPart, });
    end

    -- 处理下载结果
    local function downloadDislistResult(result)
        if result == false then
            cclog("无法下载Dislist失败");
            if callback then
                callback(false, 0);
            end
            return;
        end

        _G["dislist"] = result;

        -- 下载成功，显示下载界面
        showDownloadUI();
    end

    if (_G["dislist"] == nil) then
        -- dislist不存在，尝试下载dislist
        auLoadDislist(downloadDislistResult);
    else
        -- dislist已存在，显示下载界面
        showDownloadUI();
    end
end

-- 判断是否需要加载独立包
-- callback 后续操作回调
-- retry 失败是否继续重试
-- condition 下载判断条件回调
function checkExtraPackDownload(callback, retry, condition)
    local targetPart = "extra_pack";

    if not condition then
        -- 默认条件
        condition = function ()
            -- 3-2通关
            return DungeonAreaM.isDungeonPassed(ME.user, 32);
        end
    end

    -- 是否满足要下载的条件
    if condition() and cc.UserDefault:getInstance():getStringForKey(targetPart) ~= "1"
        and not isWindowsPlatform() then
        local function onOK()
            -- 点击确定，开始下载
            local function onDownloadResult(success, errcode)
                if success ~= true then
                    -- 下载失败
                    if IGNORE_DOWNLOAD_PKG_RESULT == 1 then
                        print("设置了忽略资源包下载失败的标记，直接走后续流程")
                        callback();
                        return;
                    end

                    local errCodeStr = string.format(getLocStr("download_pkg_fail"), errcode);

                    -- 如果设置了重试标记
                    if retry then
                        -- 提示玩家重新下载
                        local dialog = confirm2(CONFIRM_TYPE_OK, getLocStr("download_pkg_title"),errCodeStr,
                            onOK, nil, getLocStr("download_again"));
                        dialog:hideBackBtn();
                        return;
                    end

                    -- 直接飘字提示，玩家可以重新点击再次触发本流程
                    alert(errCodeStr);
                    return;
                end

                -- 下载成功，进行后续流程
                callback();
            end

            -- 下载天空之城资源包
            downloadPkg(getLocStr("download_pkg_title"), getLocStr("download_pkg_desc"), targetPart, onDownloadResult);
        end

        local function onCancel()
            if retry then
                -- 在需要保证成功的场景中，如果玩家点取消，退出游戏
                exitApp();
            end
        end

        -- 下载前提示玩家有资源包要下载，请保持网络通畅
        local dialog = confirm2(CONFIRM_TYPE_OK_CANCEL, getLocStr("download_pkg_title"), getLocStr("need_download_new_pkg"), onOK, onCancel);
        dialog:hideBackBtn();
    else
        -- 不满足条件，直接后续流程
        callback();
    end
end
---------------------
-- 显示黑屏窗口
function showBlackForm(formName)
    UIMgr.getCurrentScene():removeFormByName(formName);
    local uiSeprator = UIInvisibleForm.create();

    local frameSize = AlignM.frameSize;

    local layout = ccui.Layout:create();
    layout:setBackGroundColorType(ccui.LayoutBackGroundColorType.solid);
    layout:setBackGroundColor(cc.c3b(0, 0, 0));
    layout:setContentSize(cc.size(frameSize.width, frameSize.height));
    uiSeprator:addChild(layout);

    uiSeprator:setName(formName);
    uiSeprator:setLocalZOrder(UIMgr.TOP_MENU_ZORDER);
    UIMgr.getCurrentScene():addForm(uiSeprator);
end

---------------------
-- 隐藏黑屏窗口
function hideBlackForm(formName)
    UIMgr.getCurrentScene():removeFormByName(formName);
end

---------------------
-- 开始对白模板对话
function startDialogueTemplate(templateId, callback, extraData)
    require "game/ui/form/main/UIDialogue";
    local uiDialog = UIDialogue.create(templateId, callback, extraData);
    UIMgr.getCurrentScene():addForm(uiDialog);
end

---------------------
-- 获取奖励描述，按行隔断
-- 返回例如：（浆果X1\n浆果X2）
function getLineBreakBonusTip(bonus)
    local tip = "";
    for _, perBonus in pairs(bonus) do
        local name = "";
        if perBonus[1] == 1 then
            -- 物品
            name = ItemM.query(perBonus[2], "name");
        elseif perBonus[1] == 2 then
            -- 属性
            name = FieldsM.query(perBonus[2], "name");
        elseif perBonus[1] == 3 then
            -- 冈布奥
            name = PetM.query(perBonus[2], "name");
        elseif perBonus[1] == 6 then
            -- 秘宝
            name = SkyShipSkillM.query(perBonus[2], "name");
        elseif perBonus[1] == 8 then
            -- 机器人
            name = SkyRobotM.query(perBonus[2], "name");
        end
        -- 拼接提示
        local oneTip = string.format(getLocStr("item_bonus_format"),
            name, perBonus[3])
        tip = tip .. oneTip .. "\n";
        if node then
            table.insert(node.gainItemList, oneTip);
        end
    end
    return tip;
end

----------------
-- 统一处理显示奖励
function showBonusDesc(bonus, extraPara, showAmount)
    AudioM.playFx("workshop_material");

    -- 显示充值提示(限时礼包用到)
    if type(extraPara) == "table" and extraPara["rechargeTip"] == true then
        local goodsId = extraPara["goodsId"];

        local goodsInfo = MarketM.getGoodsInfo(goodsId);
        local desc = goodsInfo["confirm"];

        -- 没有描述
        if desc == nil or desc == "" then
            return;
        end

        desc = MarketM.parseGoodsDesc(desc, goodsInfo);

        require "game/ui/dialog/UIConfirmTip"
        local confirmTip = UIConfirmTip.create(goodsInfo["name"], desc);
        UIMgr.getCurrentScene():addDialog(confirmTip);
        return
    end

    if type(bonus) ~= "table" then
        trace("[Dialog]"," 奖励不是table类型");
        return;
    end

    if bonus[1] == 1 then
        -- 是道具， 获取道具图标
        if ItemM.query(bonus[2], "group") == 21 then
            require "game/ui/form/equips/UIEquipTooltip"
            if UIMgr.getCurrentScene():isOpen("UIEquipTooltip") then
                UIMgr.getCurrentScene():removeFormByName("UIEquipTooltip");
            end
            -- 显示道具详细信息
            local uiEquipTooltip = UIEquipTooltip.create(bonus[2]);
            UIMgr:getCurrentScene():addForm(uiEquipTooltip);
        elseif ItemM.query(bonus[2], "group") == 34 then
            -- 拼图显示道具详细信息
            require "game/ui/form/hero/UIPropertyInfo"

            UIMgr.getCurrentScene():removeFormByName("UIPropertyInfo");
            local uiProperty = UIPropertyInfo.create(bonus[2]);
            UIMgr:getCurrentScene():addForm(uiProperty);
        else
            -- 显示道具详细信息
            require "game/ui/form/workshop/UIItemDesc"
            if UIMgr.getCurrentScene():isOpen("UIItemDesc") then
                UIMgr.getCurrentScene():removeFormByName("UIItemDesc");
            end
            local uiItemDesc = UIItemDesc.create(bonus[2], nil, nil, showAmount);
            UIMgr:getCurrentScene():addForm(uiItemDesc);
        end

    elseif bonus[1] == 2 then
        -- 显示道具详细信息
        require "game/ui/form/workshop/UIItemDesc"
        if UIMgr.getCurrentScene():isOpen("UIItemDesc") then
            UIMgr.getCurrentScene():removeFormByName("UIItemDesc");
        end
        local uiItemDesc = UIItemDesc.create(bonus[2]);
        UIMgr:getCurrentScene():addForm(uiItemDesc);

    elseif bonus[1] == 3 then
        -- 显示道具详细信息
        if UIMgr.getCurrentScene():isOpen("UIHeroDetailInfo") then
            UIMgr.getCurrentScene():removeFormByName("UIHeroDetailInfo");
        end

        local uiHeroInfo = UIHeroDetailInfo.create(bonus[2]);
        UIMgr.getCurrentScene():addForm(uiHeroInfo);

    elseif bonus[1] == 6 then
        -- 显示秘宝详细信息
        require "game/ui/form/sky_city/UIAirShipSkillDesc"
        if UIMgr.getCurrentScene():isOpen("UIAirShipSkillDesc") then
            UIMgr.getCurrentScene():removeFormByName("UIAirShipSkillDesc");
        end
        local uishipSkillForm = UIAirShipSkillDesc.create(bonus[2]);
        UIMgr:getCurrentScene():addForm(uishipSkillForm);

    elseif bonus[1] == 8 then
        UIMgr:getCurrentScene():removeFormByName("UISkyStoreItem");
        require "game/ui/form/sky_city/UISkyStoreItem";
        local uiStoreItem = UISkyStoreItem.create(bonus[2], "robot", {["robot_tip"] = true});
        UIMgr.getCurrentScene():addForm(uiStoreItem);

    elseif bonus[1] == "rotine" then
        -- 常规活动
        -- 显示道具详细信息
        require "game/ui/form/workshop/UIItemDesc"
        if UIMgr.getCurrentScene():isOpen("UIItemDesc") then
            UIMgr.getCurrentScene():removeFormByName("UIItemDesc");
        end
        local uiItemDesc = UIItemDesc.create(bonus[2]);
        UIMgr:getCurrentScene():addForm(uiItemDesc);

    elseif bonus[1] == "baby" then
        -- 冈布奥宝宝
        local info = FateChainM.queryBaby(bonus[2]);
        local dialog = getLocStr("gumball_baby_desc");
        if FateChainM.isFateChainFinish(bonus[2]) then
            -- 已经完成了，才带上父母的名字
            local fatherName = PetM.query(info["father"], "short_name");
            local motherName = PetM.query(info["mother"], "short_name");
            dialog = dialog .. string.format(getLocStr("gumball_baby_desc2"), fatherName, motherName);
        end
        dialog = dialog .. "\n\n" .. "[blue]" .. info["desc"] .. "[-]";
        showCommonDesc(info["name"], dialog);
    else
        trace("[Dialog]", "请添加其他类型奖励描述");
    end
end

---------------------
-- 显示分享窗口
-- @param shareType  分享类型
-- @param title      标题
-- @param desc       描述
-- @param args       自定义参数
function showShareForm(shareType, title, desc, args)
    if isOverseaPackage() then
        -- 海外渠道
        require "game/ui/form/share/UIShareSelect";
        local uiForm = UIShareSelect.create(shareType, title, desc, args);
        UIMgr.getCurrentScene():removeFormByName("UIShareSelect");
        UIMgr.getCurrentScene():addForm(uiForm);
    else
        -- 国内渠道
        require "game/ui/form/share/UIShareSelectCN";
        local uiForm = UIShareSelectCN.create(shareType, title, desc, args);
        UIMgr.getCurrentScene():removeFormByName("UIShareSelectCN");
        UIMgr.getCurrentScene():addForm(uiForm);
    end
end

-- 显示微信和支付宝
-- @param goodsId      商品ID
function showInlandPayWay(goodsId)
    require "game/ui/form/market/UIInlandPayWay";
    local uiForm = UIInlandPayWay.create(goodsId);
    UIMgr.getCurrentScene():removeFormByName("UIInlandPayWay");
    UIMgr.getCurrentScene():addForm(uiForm);
end
--------
-- 自动领取首充礼包
function checkFirstChargeBonus()
    if MarketM.canTakeFirstChargeBonus() then
        -- 直接打开领取
        local title = getLocStr("recharge_bonus_title");
        local bonusList = FormulaM.invoke("CALC_FIRST_RECHARGE_BONUS_LIST");
        local function okFirstRecharge()
            MarketM.takeFirstCharge(bonusList);
            local uimarket = UIMgr.getCurrentScene():getFormByName("UIMarketMain");
            if uimarket then
                uimarket:showSubPage("superior", true);
            end
        end
        showBonusNotifyForm(title, bonusList, okFirstRecharge);
    end
end
----------
-- goodsInfo  商品信息{类型,ID, 数量}
-- goodsPrice 商品价格{类型,ID,数量}
-- callback   确认购买执行函数
-- 显示商品信息
function showGoodsDetail(goodsInfo, goodsPrice, callback)
    require "game/ui/form/common/UIGoodsDetail"

    UIMgr.getCurrentScene():removeFormByName("UIGoodsDetail");
    local uiform = UIGoodsDetail.create(goodsInfo, goodsPrice, callback);
    UIMgr.getCurrentScene():addForm(uiform);
end

-----------------------------------
-- 显示提示信息（活动限制提示/红标题）
-- @param title   标题
-- @param content 内容
function showActivityTip(title, content, extraBtnInfo)
    require "game/ui/dialog/UIShowTip"
    UIMgr.getCurrentScene():removeFormByName("UIShowTip");
    local uiForm = UIShowTip.create(title, content, extraBtnInfo);
    UIMgr.getCurrentScene():addForm(uiForm);
end

----------------------------------
-- 显示提示信息（蓝标题）
-- @param title  标题
-- @param desc   描述
function showCommonDesc(title, desc)
    require "game/ui/dialog/UICommonDesc"
    UIMgr.getCurrentScene():removeFormByName("UICommonDesc");
    local uiForm = UICommonDesc.create(title, desc);
    UIMgr.getCurrentScene():addForm(uiForm);
end

-- 打开补充能量界面
-- 使用电池包
function addExploreEnergy()
    -- 打开物品批量使用界面
    require "game/ui/form/item/UIItemBatchUse"
    UIMgr.getCurrentScene():removeFormByName("UIItemBatchUse");
    local activedShip = NewAirShipM.getActiveAirShip();
    local maxEnergy = FormulaM.invoke("CALC_MAX_SHIP_ENERGY", ME.user);
    local curEnergy = ME.user.dbase:query("ship_energy", 0);
    local desc = string.format(getLocStr("add_energy_desc"), curEnergy, maxEnergy);
    local form = UIItemBatchUse.create(getLocStr("add_energy_title"), desc, SkyResourceM.queryByAlias("energy", "class_id"), 5);
    UIMgr.getCurrentScene():addForm(form);
end

-- 打开天空仓库物品
function openStoreItem(classId, type, args)
    closeFormByName("UISkyStoreItem");
    require "game/ui/form/sky_city/UISkyStoreItem"
    local uiForm = UISkyStoreItem.create(classId, type, args);
    UIMgr.getCurrentScene():addForm(uiForm);
    AudioM.playFx("button_spell");
end

-- 显示能量不足确认框
function showEnergyLackConfirm()
    local msg = getLocStr("buy_energy_confirm");

    local function buyEnergy()
        local energyInfo = SkyResourceM.queryByAlias("energy");
        if not energyInfo then
            return;
        end

        -- "没有可用的电池包！" 打开电池包购买界面
        if ItemM.getAmount(ME.user, energyInfo.class_id) <= 0 then
            openStoreItem(energyInfo.class_id);
            return;
        end

        -- 打开使用的
        addExploreEnergy();
    end

    confirm2(CONFIRM_TYPE_OK, getLocStr("slime_note"), msg,
        buyEnergy, nil, getLocStr("btn_text_go"));
end

-- 显示金币不足确认框
function showMoneyLackConfirm(requireAmount,callback, cancelFunc)
    local msg = getLocStr("current_money_lack");

    local payAmount = tonumber(requireAmount);

    local ownMoney = ME.user.dbase:query("money") or 0;
    local needAmount = requireAmount - ownMoney;

    -- 需求量大于0
    if needAmount <= 0 then
        return;
    end

    local costInfo = FormulaM.invoke("CALC_DIRECT_BUY_MONEY_COST", needAmount);

    local needGem = costInfo["cost_gem"];
    local buyAmount = costInfo["buy_amount"];

    msg = string.format(msg, needGem, buyAmount);
    local function buyMoney()
        if ME.user:queryAttrib("gem") < needGem then
            showGemLackConfirm();

            if cancelFunc then
                cancelFunc(true);
            end
        else
            Operation.cmd_direct_buy_goods("money", needGem, buyAmount);

            if callback then
                callback();
            end
        end
    end

    confirm2(CONFIRM_TYPE_OK, getLocStr("title_buy_material"), msg,
            buyMoney, nil, getLocStr("btn_text_buy_material"), nil, {["backFunc"] = cancelFunc});
end

-- 显示（古遗迹碎片）不足确认框
function showScrapLackConfirm(requireAmount, callback, cancelFunc)
    local msg = getLocStr("current_relic_scrap_lack");

    local payAmount = tonumber(requireAmount);

    local ownScrap = ItemM.getAmount(ME.user, 10000);
    local needAmount = requireAmount - ownScrap;

    -- 需求量大于0
    if needAmount <= 0 then
        return;
    end

    local costInfo = FormulaM.invoke("CALC_DIRECT_BUY_SCRAP_COST", needAmount);

    local needGem = costInfo["cost_gem"];
    local buyAmount = costInfo["buy_amount"];

    msg = string.format(msg, needGem, buyAmount);

    local function buyScrap()
        if ME.user:queryAttrib("gem") < needGem then
            showGemLackConfirm();

            if cancelFunc then
                cancelFunc(true);
            end
        else
            Operation.cmd_direct_buy_goods("relic_scrap", needGem, buyAmount);

            if callback then
                callback();
            end
        end
    end

    confirm2(CONFIRM_TYPE_OK, getLocStr("title_buy_material"), msg,
        buyScrap, cancelFunc, getLocStr("btn_text_buy_material"), nil, {["backFunc"] = cancelFunc});
end

-- 奖励提示
function alertBuyGoodsTip(bonusInfo)
    -- 提示购买的数量
    local str = "";
    local tip = getLocStr("buy_goods_done");
    local bonusList;
    if type(bonusInfo[1]) == "number" then
        bonusList = {bonusInfo};
    elseif type(bonusInfo[1]) == "table" then
        bonusList = bonusInfo;
    end

    for _, bonus in pairs(bonusList) do
        local name;
        local amount = bonus[3];

        if bonus[1] == 1 then
            name = ItemM.query(bonus[2], "name");
        else
            name = FieldsM.getFieldName(bonus[2]);
        end

        str = str .. string.format(tip, name, amount) .. "\n";
    end

    alert(str);
end

-- 打开雕像信息界面
function openCarvingInfoDialog(petId)
    local title = "[blue]" .. string.format(getLocStr("awake_carving_tip_title"), PetM.query(petId, "short_name")) .. "[-]";
    local desc = getLocStr("awake_carving_tip_desc");
    local propStr = AwakeM.fetchAwakeCarvingPropsDesc(petId, true);
    desc = desc .. "\n\n[blue]" .. propStr[1] .. "[-]";

    if AwakeM.awakeCarvingPropIsMaxNum(petId) then
        desc = desc .. "\n[blue]" .. propStr[2] .. "[-]" .. getLocStr("can_refresh_awake_prop");
    else
        desc = desc .. "\n[green]" .. propStr[2] .. "[-]" .. getLocStr("can_refresh_awake_prop");
    end

    -- 已建造雕像的话，打开雕像说明界面
    local function callback()
        -- 打开重铸界面
        require "game/ui/form/awake/UIAwakeRefreshProp"
        if UIMgr.getCurrentScene():isOpen("UIAwakeRefreshProp") then
            UIMgr.getCurrentScene():removeFormByName("UIAwakeRefreshProp");
        end
        local uiForm = UIAwakeRefreshProp.create(petId);
        UIMgr.getCurrentScene():addForm(uiForm);
    end

    local extraInfo = {
        ["btn_text"] = getLocStr("btn_text_awake_refresh_prop"),
        ["callback"] = callback,
    }

    showActivityTip(title, desc, extraInfo);
end